package com.jiliason.segmentation.doMain.event;

import com.google.common.collect.Lists;
import com.jiliason.segmentation.constant.Ct;
import com.jiliason.segmentation.constant.enums.Addr;
import com.jiliason.segmentation.constant.enums.Regex;
import com.jiliason.segmentation.constant.enums.Strategy;
import com.jiliason.segmentation.entity.address.AddressUnitPojo;
import com.jiliason.segmentation.entity.mySql.PCDTPojo;
import com.jiliason.segmentation.entity.splitterStrategy.StrategyInPojo;
import com.jiliason.segmentation.entity.splitterStrategy.TypePojo;
import com.jiliason.segmentation.repository.mySql.PCDTRepository;
import com.jiliason.segmentation.utils.StrUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class AddrDictSegment {

    @Resource
    private PCDTRepository pcdtRepository;

    @Resource
    private TypeSplitter typeSplitter;

    protected final String Tag = Ct.AddrDict;

    public List<AddressUnitPojo> divide(StrategyInPojo in) throws Exception {
        AddressUnitPojo prov = splitProv(in);
        AddressUnitPojo city = splitCity(in, prov);
        AddressUnitPojo dist = splitDist(in, prov, city);
        AddressUnitPojo town = splitTown(in, prov, city, dist);

        return Lists.newArrayList(prov, city, dist, town);
    }

    public AddressUnitPojo splitProv(StrategyInPojo in) throws Exception {

        List<AddressUnitPojo> provesInfo = getProvesInfo();

        return splitPCDT(in, provesInfo, Addr.PROV_NAME, Addr.PROV_TYPE);

    }

    /**
    * @description _
    * @param in,prov 被分割对象，分割后的省份信息
    * @return 分割后的城市信息
    * @date 2023/12/27
    * @author sjy
    */
    public AddressUnitPojo splitCity(StrategyInPojo in, AddressUnitPojo prov) throws Exception {

        List<AddressUnitPojo> citiesInfo = getCitiesInfo(prov);

        return splitPCDT(in, citiesInfo, Addr.CITY_NAME, Addr.CITY_TYPE);
    }

    /**
    * @description _
    * @param in,prov,city 被分割对象，分割后的省份信息，分割后的城市信息
    * @return 分割后的区县信息
    * @date 2023/12/27
    * @author sjy
    */
    public AddressUnitPojo splitDist(StrategyInPojo in, AddressUnitPojo prov, AddressUnitPojo city) throws Exception {
        List<AddressUnitPojo> distInfos = getDistInfos(prov, city);

        return splitPCDT(in, distInfos, Addr.DIST_NAME, Addr.DIST_TYPE);
    }

    /**
    * @description _
    * @param in,prov,city,dist 被分割对象，分割后的省份信息，分割后的城市信息，分割后的区县信息
    * @return 被分割后的乡镇信息
    * @date 2023/12/27
    * @author sjy
    */
    public AddressUnitPojo splitTown(StrategyInPojo in, AddressUnitPojo prov, AddressUnitPojo city, AddressUnitPojo dist) throws Exception {
        List<AddressUnitPojo> townsInfo = getTownsInfo(prov, city, dist);
        String bk = in.getAddrStr();
        AddressUnitPojo town = splitPCDT(in, townsInfo, Addr.TOWN_NAME, Addr.TOWN_TYPE);
        if (!StringUtils.equals(Strategy.M.c(), town.getSegStatus())) return town;

        // town 段有歧义，不是全称分割 且 其后紧跟 数字（中 alb L） 一律取消匹配
        String regex = town.getFiledValue() + "(" + StrUtil.combineRegex(Regex.cr1.v(), Regex.cr2.v(), Regex.cr3.v()) + ")";
        Matcher matcher = Pattern.compile(regex).matcher(bk);
        if (!town.isCompleteShortFlag() && matcher.find()) {
            town.setSegStatus(Strategy.E.c());
            in.setAddrStr(bk);
        }
        return town;
    }

    public AddressUnitPojo splitPCDT(StrategyInPojo in, List<AddressUnitPojo> PCDTInfo, Addr addr, Addr addrType) {

        // 初期化PCDT段分割结果
        AddressUnitPojo PCDTUnit = new AddressUnitPojo(addr, Tag, addr.i());
        PCDTUnit.setTypeFiledName(addrType);
        PCDTUnit.setSegStatus(Strategy.E.c());

        // 全称分割，如果有分割结束
        boolean f = completeNameSplit(in, PCDTUnit, PCDTInfo);
        if (f) return PCDTUnit;
        // 简称分割
        shortNameSplit(in, PCDTUnit, PCDTInfo);
        return PCDTUnit;
    }

    private boolean completeNameSplit(StrategyInPojo in, AddressUnitPojo PCDTUnit, List<AddressUnitPojo> PCDTInfo) {
        // 全称分割，如果有分割结束
        List<AddressUnitPojo> candidateList = PCDTInfo.stream()
                .filter(iu -> in.getAddrStr().contains(iu.getFiledValue()))
                .toList();

        if (candidateList.isEmpty()) return false;

        int index = candidateList.stream()
                .min(Comparator.comparing(iu -> in.getAddrStr().indexOf(iu.getFiledValue())))
                .map(candidateList::indexOf).orElse(-1);

        if (index >= 0) {
            AddressUnitPojo provUnit = candidateList.get(index);
            String fullName = provUnit.getFiledValue();
            String name = provUnit.getName();
            String type = provUnit.getType();

            PCDTUnit.setFiledValue(fullName);
            PCDTUnit.setName(name);
            PCDTUnit.setType(type);
            PCDTUnit.setSegStatus(Strategy.M.c());
            // 全称分割
            PCDTUnit.setCompleteShortFlag(true);

            in.split(fullName);

            return true;
        }
        return false;
    }

    private void shortNameSplit(StrategyInPojo in, AddressUnitPojo PCDTUnit, List<AddressUnitPojo> PCDTInfo) {
        List<AddressUnitPojo> candidateList = PCDTInfo.stream()
                .filter(iu -> in.getAddrStr().contains(iu.getName()))
                .toList();

        if (candidateList.isEmpty()) return;

        int index = candidateList.stream()
                .min(Comparator.comparing(iu -> in.getAddrStr().indexOf(iu.getName())))
                .map(candidateList::indexOf).orElse(-1);

        if (index >= 0) {
            AddressUnitPojo provUnit = candidateList.get(index);
            String name = provUnit.getName();
            String orgType = typeSplitter.useNameSplitType(in, name);

            PCDTUnit.setFiledValue(name + orgType);
            PCDTUnit.setName(name);
            PCDTUnit.setType(orgType);
            PCDTUnit.setSegStatus(Strategy.M.c());
            in.split(name + orgType);
        }
    }

    private List<AddressUnitPojo> getProvesInfo() throws Exception {
        // 获取词库省份信息
        List<String> provesInfo = pcdtRepository.getPRC_ProvInfo().stream().filter(StringUtils::isNotEmpty).toList();
        return formatWordDictInfo(provesInfo, Regex.ar1);
    }

    private List<AddressUnitPojo> getCitiesInfo(AddressUnitPojo prov) throws Exception {

        PCDTPojo in = PCDTPojo.builder()
                .prov(prov.getFiledValue())
                .provFlag(prov.isCompleteShortFlag())
                .build();
        List<String> citiesInfo = pcdtRepository.getPRC_CityInfo(in);
        return formatWordDictInfo(citiesInfo, Regex.ar2);
    }

    private List<AddressUnitPojo> getDistInfos(AddressUnitPojo prov, AddressUnitPojo city) throws Exception {
        Optional<AddressUnitPojo> op_prov = Optional.ofNullable(prov);
        Optional<AddressUnitPojo> op_city = Optional.ofNullable(city);
        PCDTPojo in = PCDTPojo.builder()
                .prov(op_prov.map(AddressUnitPojo::getFiledValue)
                        .orElse(null))
                .city(op_city.map(AddressUnitPojo::getFiledValue)
                        .orElse(null))
                .provFlag(op_prov.map(AddressUnitPojo::isCompleteShortFlag)
                        .orElse(true))
                .cityFlag(op_city.map(AddressUnitPojo::isCompleteShortFlag)
                        .orElse(true))
                .build();
        List<String> distInfos = pcdtRepository.getPRC_DistInfo(in);
        return formatWordDictInfo(distInfos, Regex.ar3);
    }

    private List<AddressUnitPojo> getTownsInfo(AddressUnitPojo prov, AddressUnitPojo city, AddressUnitPojo dist) throws Exception {
        Optional<AddressUnitPojo> op_prov = Optional.ofNullable(prov);
        Optional<AddressUnitPojo> op_city = Optional.ofNullable(city);
        Optional<AddressUnitPojo> op_dist = Optional.ofNullable(dist);

        PCDTPojo in = PCDTPojo.builder()
                .prov(op_prov.map(AddressUnitPojo::getFiledValue)
                        .orElse(null))
                .city(op_city.map(AddressUnitPojo::getFiledValue)
                        .orElse(null))
                .dist(op_dist.map(AddressUnitPojo::getFiledValue)
                        .orElse(null))
                .provFlag(op_prov.map(AddressUnitPojo::isCompleteShortFlag)
                    .orElse(true))
                .cityFlag(op_city.map(AddressUnitPojo::isCompleteShortFlag)
                    .orElse(true))
                .distFlag(op_dist.map(AddressUnitPojo::isCompleteShortFlag)
                    .orElse(true))
                .build();
        List<String> townsInfo = pcdtRepository.getPRC_TownInfo(in);
        return formatWordDictInfo(townsInfo, Regex.ar4);
    }

    private List<AddressUnitPojo> formatWordDictInfo(List<String> infos, Regex regex) throws Exception {
        infos = infos.stream().filter(StringUtils::isNotEmpty).toList();
        List<AddressUnitPojo> units = Lists.newArrayList();
        for (String info : infos) {
            TypePojo typeEntity = typeSplitter.fieldSplitType(info, regex);
            AddressUnitPojo cu = new AddressUnitPojo();
            cu.setFiledValue(info);
            cu.setName(typeEntity.getName());
            cu.setType(typeEntity.getType());
            units.add(cu);
        }

        return units;
    }

}
